/**	
 * Author : Mht
 * Desc : For 2016 RDM 
 */
package dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

/**
 * @author Mht
 * @date May 10, 2016
 */

public abstract class AbstractRedisBaseDao<K, V> {

	private static final Logger log = LoggerFactory.getLogger(AbstractRedisBaseDao.class);

	@Autowired
	protected RedisTemplate redisTemplate;

	/**
	 * Set redisTemplate
	 * 
	 * @param redisTemplate
	 *            the redisTemplate to set
	 */
	protected void setRedisTemplate(RedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	/**
	 * Get RedisSerializer <br>
	 * ------------------------------<br>
	 */
	protected RedisSerializer getRedisSerializer() {
		return redisTemplate.getStringSerializer();
	}

	/**
	 * 批量向redis中插入H码:key(tableName:hcode) value(pcode)
	 * 如果键已存在则返回false,不更新,防止覆盖。使用pipeline批处理方式(不关注返回值)
	 * 
	 * @param list
	 *            一个map代表一行记录,2个key:hcode & pcode。
	 * @param tableName
	 *            redis中key的值为tableName:hcode 对应value值为pcode。
	 * @return
	 */
	public boolean addHcode(final String tableName, final List<Map<String, Object>> list, final String ... parameters) {
		log.info("Add hash Map");
		boolean result = (boolean) redisTemplate.execute(new RedisCallback<Boolean>() {
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				for (Map<String, Object> map : list) {
					byte[] key = serializer.serialize(tableName + ":" + map.get(parameters[0]).toString());
					byte[] name = serializer.serialize(map.get(parameters[1]).toString());
					connection.setNX(key, name);
				}
				return true;
			}
		}, false, true);
		return result;
	}

	/**
	 * 从redis中获取key rPop从链表尾部弹出对应的value 多线程并发读取日志长度的时候，比如都得到结果是1000条。 当多线程每个都
	 * 循环1000次 pop弹出的时候， 由于是多线程一起pop，所以每个线程获得的数组中都会包含 null 甚至有的全是null
	 * 
	 * @return
	 */
	public List<String> get(final String key) {

		final RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
		// 对应key的List长度
		final Long listSize = redisTemplate.opsForList().size(key);

		List<Object> list = redisTemplate.executePipelined(new RedisCallback<String>() {
			@Override
			public String doInRedis(RedisConnection conn) throws DataAccessException {
				for (int i = 0; i < listSize; i++) {
					byte[] listName = serializer.serialize(key);
					conn.rPop(listName);
				}
				return null;
			}
		}, serializer);

		// 去除结果中的null
		ArrayList<String> newList = new ArrayList<String>();
		for (Object o : list) {
			if (o != null)
				newList.add(String.valueOf(o));
		}
		return newList;
	}

	/**
	 * 向redis中插入key-value leftPush 从链表头部压入
	 * 
	 * @return
	 */
	public void insert(final String key, final V value) {
		log.info("Insert into redis : [ key = " + key + " value = " + value + " ]");
		try {
			redisTemplate.opsForList().leftPush(key, value);
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}

	public void insert(final String key, final List<V> value) {
		log.info("Insert into redis : [ key = " + key + " value = " + value.toString() + " ]");
		try {
			redisTemplate.opsForList().leftPushAll(key, value);
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}
	
	public void insert(final String key, final String value) {
		log.info("Insert into redis : [ key = " + key + " value = " + value + " ]");
		try {
			redisTemplate.opsForList().leftPush(key, value);
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}
}
